package com.cictec.middleware.tde.rm.protocol;

import java.nio.ByteBuffer;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.AttributeKey;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.cictec.middleware.commons.utils.BinaryUtils;
import com.cictec.middleware.tde.exception.EscapeException;
import com.cictec.middleware.tde.exception.IllegalMessageException;
import com.cictec.middleware.tde.rm.protocol.TerminalMessage.Header;
import com.cictec.middleware.tde.rm.protocol.rm.ProtocelConstants;
import com.cictec.middleware.tde.rm.protocol.rm.utils.RmBinaryUtils;

@Component
public class TerminalProtocolDecoder extends CumulativeProtocolDecoder {

	private static Logger logger = LoggerFactory.getLogger(TerminalProtocolDecoder.class);

	private final AttributeKey MESSAGE_STARTED = new AttributeKey(getClass(), "MessageStarted");
	private final AttributeKey PREVIOUS_BYTE = new AttributeKey(getClass(), "PreviousByte");

	@Autowired
	private MessageCodecFounder messageCodecFounder;

	@Override
	protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
//		  int startPosition = in.position();
//		  byte[] bytestest = new byte[10];
//		 while(in.hasRemaining()){
//	            byte b = in.get();
//	           
//	                int curPosition = in.position();
//	                int limit = in.limit();
//	                in.position(startPosition);
//	                in.limit(curPosition);
//	                IoBuffer buf = in.slice();
//	                byte[] bytes = new byte[buf.limit()];
//	                buf.get(bytes);
//	               System.out.println(BinaryUtils.byte2HexStr(bytes));
//	                in.position(curPosition);
//	                in.limit(limit);
//	                bytestest=bytes;
//	            
//	        }
//		 logger.error("消息 {} 对应的解码器 ", BinaryUtils.byte2HexStr(bytestest));
//		  System.out.println("完成消息："+BinaryUtils.byte2HexStr(bytestest));
//		// Remember the initial position.
		int start = 0;

		boolean started = false;
		//session.setAttribute(MESSAGE_STARTED,true);
		// 周琦测试
		// session.setAttribute(MESSAGE_STARTED, true);
		// 周琦测试
		if (session.getAttribute(MESSAGE_STARTED) != null) {
			started = (Boolean) session.getAttribute(MESSAGE_STARTED);
		}

//		System.out.print("started--" + started + "---");
		int size = -1;

		byte previous = 0;
		if (session.getAttribute(PREVIOUS_BYTE) != null) {
			previous = (Byte) session.getAttribute(PREVIOUS_BYTE);
		}
//		System.out.print("previous--" + previous);
		// previous=Constants.MESSAGE_BEGIN_FLAG
		StringBuffer sb = new StringBuffer();
		int counter = 0;

		// 测试
		// started=true;
		// size=0;
		// 周琦测试
		// size=0;
		// 周琦测试
		while (in.hasRemaining()) {
			int position = in.position();
			int limit = in.limit();

			byte current = in.get();

			sb.append(BinaryUtils.byte2HexStr(current)).append(' ');
			
			//sb.append(current).append(' ');

			if (started) {
				// logger.debug("当前的Size {}",size);
				if (size == -1) {
					size = BinaryUtils.unsignedByteToInt(current) + 1;
				} else if (size == 0) {

					try {
						in.position(start);
						in.limit(position);

						byte[] bytes = new byte[position - start];

						in.get(bytes);

						int valiCode = 0;
						for (int i = 1; i < bytes.length - 1; i++) {
							valiCode = valiCode ^ BinaryUtils.unsignedByteToInt(bytes[i]);
						}

						ByteBuffer msgBuffer = ByteBuffer.wrap(bytes);

						Header header = decodeHeader(msgBuffer);

						logger.debug("收到消息 Session {} 序号{} 消息ID 0x{} : {} ", 
								session.getId(), 
								header.getMessageSequence(),
								BinaryUtils.byte2HexStr(BinaryUtils.intToUnsignedByte(header.getMessageId())),
								BinaryUtils.byte2HexStr(bytes));
						
						MessageDecoder md = this.messageCodecFounder.getDecoder(header.getMessageId());

						if (md != null) {
							TerminalMessage tm = md.decode(header, msgBuffer, session);
							tm.setSessionId(session.getId());
							out.write(tm);
							counter++;
						} else {
							logger.error("找不到消息 0x{} 对应的解码器 ", Integer.toHexString(header.getMessageId()));
						}

					} catch (Throwable t) {
						logger.error("解码错误", t);
					} finally {
						in.position(position);
						in.limit(limit);
					}
					started = false;

					session.setAttribute(MESSAGE_STARTED, new Boolean(started));
					session.setAttribute(PREVIOUS_BYTE, new Byte(current));
					if (logger.isDebugEnabled()) {
//						logger.debug("收到数据并且解码成功 Session {} ： {}", session.getId(), sb.toString());
					}
					return true;
				} else {
					size--;
				}
			} else if (previous == ProtocelConstants.MESSAGE_BEGIN_FLAG && current == ProtocelConstants.MESSAGE_BEGIN_FLAG) {
				start = in.position();
				started = true;
				size = -1;
//				logger.debug("发现消息开始 {} ", start);
			}

			previous = current;
		}
//		logger.debug("缓冲区遍历完成 此时 Position 为 {} 开始标志 {} 开始位置 {}", in.position(), started, start);
		session.setAttribute(MESSAGE_STARTED, new Boolean(started));
		session.setAttribute(PREVIOUS_BYTE, new Byte(previous));
		if (started) {
			in.position(start);
		}

		if (logger.isDebugEnabled()) {
//			logger.debug("收到数据 解码未完成 Session {} ： {}", session.getId(), sb.toString());
		}
		return false;

	}


	protected Header decodeHeader(ByteBuffer in) throws EscapeException, IllegalMessageException {

		Header header = new Header(0);

		int length = BinaryUtils.unsignedByteToInt(in);
		header.setBodyLength(length);

		int verNum = BinaryUtils.unsignedByteToInt(in);
		String ver = (verNum >> 4) + "." + (verNum & 0x0f);
		header.setVersion(ver);

		header.setMessageSequence(BinaryUtils.unsignedByteToInt(in));

		header.setMessageId(BinaryUtils.unsignedByteToInt(in));

		header.setSendTime(RmBinaryUtils.dwordToDateRM(in));

//		byte[] byteId = new byte[4];
//		in.get(byteId, 1, 3);
//		byteId[0] = 0;
		
		byte[] byteId = new byte[4];
		in.get();
		in.get(byteId,2,2);
		byteId[0] = 0;
		byteId[1] = 0;
		
		long terminalId = BinaryUtils.dwordToLong(byteId);
		header.setTerminalId((int) terminalId);

		header.setLineId(BinaryUtils.wordToInt(in));

		return header;
	}

}
